package logica;

import personaje.*;
import nivel.*;

/**
 * Clase que modela la logica de los movimientos de Mario. Se encarga de
 * reportar a Mario si puede realizar un movimiento o no.
 * 
 * @author Agustin Orge (LU.85538)
 * @author Victoria Martinez de la Cruz (LU.87620)
 */
public class Logica {

	/** Mario. */
	private Mario mario;

	/** Atributo que modela si mario esta cayendo o no. */
	private boolean estaCayendo;

	/** Atributo que modela si mario esta saltando o no. */
	private boolean estaSaltando;

	/** Cantidad de saltos realizados. */
	private int cantSaltos;

	/**
	 * Constructor de la clase logica. Inicializa los atributos.
	 * 
	 * @param m
	 *            Mario
	 */
	public Logica(Mario m) {
		mario = m;
		estaCayendo = false;
		estaSaltando = false;
		cantSaltos = 0;
	}

	// Consultas

	/**
	 * Retorna si se puede mover a la posicion (x,y)
	 * 
	 * @param x
	 *            posicion en el eje x
	 * @param y
	 *            posicion en el eje y
	 * @return true, si puede mover
	 */
	private boolean puedeMover(int x, int y) {

		Casillero ca = mario.getNivel().getTablero().buscarCasillero(x, y);

		if (ca == null) { // no existe el casillero, se puede mover
			return true;
		} else { // existe el casillero, reacciona el obstaculo

			return ca.getObstaculo().reaccionar(mario);
		}
	}

	/**
	 * Reporta si se puede caer a la posicion (x,y). La busca en el tablero.
	 * 
	 * @param x
	 *            posicion en el eje x
	 * @param y
	 *            posicion en el eje y
	 * @return true, si puede caer
	 */
	private boolean puedeCaer(int x, int y) {

		Casillero ca = mario.getNivel().getTablero().buscarCasillero(x, y);
		boolean retorno;

		if (ca == null) {
			return true;
		} else { // hay casillero, entonces reacciona con el obstaculo
			retorno = ca.getObstaculo().reaccionar(mario);

			return retorno;
		}
	}

	/**
	 * Reporta si se encuentra a nivel del piso.
	 * 
	 * @param y
	 *            posicion en el eje y
	 * @return true, si se encuentra en el piso
	 */
	private boolean enPiso(int y) {
		if (y == 208) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Reporta si puede caer desde la posicion en la que se encuentra.
	 * 
	 * @return true, si puede caer
	 */
	public boolean caer() {

		if (!estaSaltando) {

			boolean abajo, abajoIzq, abajoDer;

			abajo = puedeCaer(mario.getCasilleroActual().getX(), mario
					.getCasilleroActual().getY() + 16);
			abajoIzq = puedeCaer(mario.getCasilleroActual().getX() - 8, mario
					.getCasilleroActual().getY() + 16);
			abajoDer = puedeCaer(mario.getCasilleroActual().getX() + 8, mario
					.getCasilleroActual().getY() + 16);

			if (enPiso(mario.getCasilleroActual().getY() + 16)) {
				return ((!abajoIzq && !abajoDer) || !abajo);
			} else {
				return (abajoIzq && abajoDer && abajo);
			}
		} else {
			return false;
		}
	}

	/**
	 * Reporta si puede saltar desde la posicion en la que se encuentra.
	 * 
	 * @return true, si puede saltar
	 */
	public boolean saltar() {

		if (!estaCayendo) {

			boolean arriba, arribaIzq, arribaDer;

			arriba = puedeMover(mario.getCasilleroActual().getX(), mario
					.getCasilleroActual().getY() - 16);
			arribaIzq = puedeMover(mario.getCasilleroActual().getX() - 8, mario
					.getCasilleroActual().getY() - 16);
			arribaDer = puedeMover(mario.getCasilleroActual().getX() + 8, mario
					.getCasilleroActual().getY() - 16);

			return (arribaIzq && arriba && arribaDer);
		} else {
			return false;
		}

	}

	/**
	 * Reporta si se puede mover a la derecha desde la posicion en la que se
	 * encuentra.
	 * 
	 * @return true, si se puede mover a la derecha
	 */
	public boolean moverDerecha() {
		boolean derecha, derechaArriba, derechaAbajo;

		derecha = puedeMover(mario.getCasilleroActual().getX() + 16, mario
				.getCasilleroActual().getY());
		derechaArriba = puedeMover(mario.getCasilleroActual().getX() + 16,
				mario.getCasilleroActual().getY() - 8);
		derechaAbajo = puedeMover(mario.getCasilleroActual().getX() + 16, mario
				.getCasilleroActual().getY() + 8);

		return (derecha && derechaArriba && derechaAbajo);
	}

	/**
	 * Reporta si se puede mover a la izquierda desde la posicion en la que se
	 * encuentra.
	 * 
	 * @return true, si se puede mover a la izquierda
	 */
	public boolean moverIzquierda() {
		boolean izquierda, izquierdaArriba, izquierdaAbajo;

		// si mario esta en el inicio del mapa, no puede moverse hacia la
		// izquierda

		if (mario.getCasilleroActual().getX() == 192) {
			return false;
		} else {

			izquierda = puedeMover(mario.getCasilleroActual().getX() - 16,
					mario.getCasilleroActual().getY());
			izquierdaArriba = puedeMover(
					mario.getCasilleroActual().getX() - 16, mario
							.getCasilleroActual().getY() - 8);
			izquierdaAbajo = puedeMover(mario.getCasilleroActual().getX() - 16,
					mario.getCasilleroActual().getY() + 8);

			return (izquierda && izquierdaAbajo && izquierdaArriba);
		}

	}

	/**
	 * Retorna la cantidad de saltos realizados.
	 * 
	 * @return cantidad de saltos realizados
	 */
	public int cantSaltos() {
		return cantSaltos;
	}

	/**
	 * Reporta si esta cayendo o no.
	 * 
	 * @return true, si esta cayendo
	 */
	public boolean estaCayendo() {
		return estaCayendo;
	}

	/**
	 * Reporta si esta saltando o no.
	 * 
	 * @return true, si esta saltando
	 */
	public boolean estaSaltando() {
		return estaSaltando;
	}

	// Comandos

	/**
	 * Modifica el valor del atributo estaCayendo
	 * 
	 * @param b
	 *            nuevo valor
	 */
	public void setCayendo(boolean b) {
		estaCayendo = b;
	}

	/**
	 * Modifica el valor del atributo estaSaltando
	 * 
	 * @param b
	 *            nuevo valor
	 */
	public void setSaltando(boolean b) {
		estaSaltando = b;
	}

	/**
	 * Aumenta en uno la cantidad de saltos realizados.
	 */
	public void aumentarSaltos() {
		cantSaltos++;
	}

	/**
	 * Vuelve la cantidad de saltos realizados a cero.
	 */
	public void resetearSaltos() {
		cantSaltos = 0;
	}

}
